home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / bmutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-28  |  24.3 KB  |  1,065 lines

  1. /*
  2.  *    Simple mail user interface for KA9Q IP/TCP package.
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.  *    Permission granted for non-commercial copying and use, provided
  9.  *    this notice is retained.
  10.  *
  11.  *    Ported to NOS at 900120 by Anders Klemets SM0RGV.
  12.  */
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <time.h>
  17. #include "global.h"
  18. #include "socket.h"
  19. #include "ftpserv.h"
  20. #include "smtp.h"
  21. #include "proc.h"
  22. #include "usock.h"
  23. #include "telnet.h"
  24. #include "session.h"
  25. #include "files.h"
  26.  
  27. #undef        SETVBUF
  28.  
  29. #if    defined(UNIX) || defined(MICROSOFT)
  30. #include    <sys/types.h>
  31. #endif
  32.  
  33. #if    defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
  34. #include    <sys/stat.h>
  35. #endif
  36.  
  37. #ifdef AZTEC
  38. #include <stat.h>
  39. #endif
  40.  
  41. #include <fcntl.h>
  42. #include "bm.h"
  43. #include "mailbox.h"
  44.  
  45. #ifdef SETVBUF
  46. #define        MYBUF    512
  47. static char    *stdinbuf = NULLCHAR;    /* the stdio buffer for the mail file */
  48. static char    *stdoutbuf = NULLCHAR;    /* the stdio file io buffer for the temp file */
  49. #endif
  50.  
  51. extern int Mbmore;
  52.  
  53. static char Badmsg[] = "Invalid Msg# %d\n";
  54. static char Nomail[] = "No messages\n";
  55. static char Fileerr[] = "Error writing mail file\n";
  56.  
  57. char No[] = "*** NO\n";            /* also used in mailbox.c */
  58.  
  59. static int near tkeywait __ARGS((char *prompt,int flush));
  60. static void near mfclose __ARGS((struct mbx *m));
  61. static int near readnotes __ARGS((struct mbx *m,FILE *ifile,int update));
  62. static long near fsize __ARGS((char *name));
  63. static int near initnotes __ARGS((struct mbx *m));
  64.  
  65. /* close the temporary mail file */
  66. static void near
  67. mfclose(m)
  68. struct mbx *m;
  69. {
  70.     if(m->mfile != NULLFILE)
  71.         fclose(m->mfile);
  72.     m->mfile = NULLFILE;
  73. #ifdef SETVBUF
  74.     xfree(stdoutbuf);
  75.     stdoutbuf = NULLCHAR;
  76. #endif
  77. }
  78.  
  79. /* list headers of a notesfile a message */
  80. int
  81. dolistnotes(argc,argv,p)
  82. int argc;
  83. char *argv[];
  84. void *p;
  85. {
  86.     struct    let *cmsg;
  87.     char *cp, *s, type, smtp_date[SLINELEN], smtp_from[SLINELEN];
  88.     char smtp_subject[SLINELEN], tstring[LINELEN], area[80], buf[80];
  89.     int    start, stop;
  90.     long size;
  91.     struct mbx *m = (struct mbx *) p;
  92.     int isareap = isarea(m->area);
  93.  
  94.     if(m->security && !isareap)
  95.         return 0;
  96.  
  97.     strcpy(area,m->area);
  98.     while((cp = strchr(area,'/')) != NULLCHAR)
  99.         *cp = '.';
  100.     sprintf(buf,"Area %s: ",area);
  101.  
  102.     if(!m->nmsgs || m->mfile == NULLFILE) {
  103.         usputs(m->user,buf);
  104.         usputs(m->user,Nomail);
  105.         return 0;
  106.     }
  107.  
  108.     usprintf(m->user,"%s%d message%s",buf,m->nmsgs,m->nmsgs == 1 ? "" : "s");
  109.     if(!isareap && m->newmsgs)
  110.         usprintf(m->user," - %d new",m->newmsgs);
  111.     usputs(m->user,"\n");
  112.  
  113.     stop = m->nmsgs;
  114.     if(m->stype == 'L') {        /* LL (List Latest) command */
  115.         start = stop - ((argc > 1) ? (atoi(argv[1]) - 1) : 0);
  116.     } else {
  117.         start = (argc < 2) ? 1 : atoi(argv[1]);
  118.         if(argc > 2)
  119.             stop = atoi(argv[2]);
  120.     }
  121.     if(stop > m->nmsgs)
  122.         stop = m->nmsgs;
  123.     if(start < 1)
  124.         start = 1;
  125.     if(start > stop)
  126.         stop = start;
  127.     for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
  128.         *smtp_date = '\0';
  129.         *smtp_from = '\0';
  130.         *smtp_subject = '\0';
  131.         type = ' ';
  132.         fseek(m->mfile,cmsg->start,0);
  133.         size = cmsg->size;
  134.         while (size > 0
  135.           && fgets(tstring,sizeof(tstring),m->mfile) != NULLCHAR) {
  136.             if (*tstring == '\n')    /* end of header */
  137.                 break;
  138.             size -= strlen(tstring);
  139.             rip(tstring);
  140.             /* handle continuation later */
  141.             if (*tstring == ' '|| *tstring == '\t')
  142.                 continue;
  143.             switch(htype(tstring)) {
  144.             case FROM:
  145.                 cp = getaddress(tstring,0);
  146.                 sprintf(smtp_from,"%.30s",cp != NULLCHAR ? cp : "");
  147.                 break;
  148.             case SUBJECT:
  149.                 sprintf(smtp_subject,"%.34s",&tstring[9]);
  150.                 break;
  151.             case DATE:
  152.                 if ((cp = strchr(tstring,',')) == NULLCHAR)
  153.                     cp = &tstring[6];
  154.                 else
  155.                     cp++;
  156.                 /* skip spaces */
  157.                 while (*cp == ' ') cp++;
  158.                 if(strlen(cp) < 17)
  159.                     break;     /* not a valid length */
  160.                 s = smtp_date;
  161.                 /* copy day */
  162.                 if (atoi(cp) < 10 && *cp != '0') {
  163.                     *s++ = ' ';
  164.                 } else
  165.                     *s++ = *cp++;
  166.                 *s++ = *cp++;
  167.  
  168.                 *s++ = ' ';
  169.                 *s = '\0';
  170.                 while (*cp == ' ')
  171.                     cp++;
  172.                 strncat(s,cp,3);    /* copy month */
  173.                 cp += 3;
  174.                 while (*cp == ' ')
  175.                     cp++;
  176.                 /* skip year */
  177.                 while (isdigit(*cp))
  178.                     cp++;
  179.                 /* copy time */
  180.                 strncat(s,cp,6); /* space hour : min */
  181.                 break;
  182.             case BBSTYPE:
  183.                 type = tstring[16];
  184.                 break;
  185.             case NOHEADER:
  186.                 break;
  187.             }
  188.         }
  189.         if((type == m->stype && m->stype != ' ')
  190.           || m->stype == ' '|| m->stype == 'L')
  191.             usprintf(m->user,"%c%c%c%3d %-27.27s %-12.12s %6ld %.23s\n",
  192.                 (start == m->current ? '>' : ' '),
  193.                 (cmsg->status & BM_DELETE ? 'D' : ' '),
  194.                 (cmsg->status & BM_READ ? 'Y' : 'N'),
  195.                 start, smtp_from, smtp_date,
  196.                 cmsg->size, smtp_subject);
  197.     }
  198.     return 0;
  199. }
  200.  
  201. /*  save msg on stream - if noheader set don't output the header */
  202. int
  203. msgtofile(m,msg,tfile,noheader)
  204. struct mbx *m;
  205. int msg;
  206. FILE *tfile;   /* already open for write */
  207. int noheader;
  208. {
  209.     char    tstring[LINELEN];
  210.     long     size;
  211.  
  212.     if (m->mfile == NULLFILE) {
  213.         tputs(Nomail);
  214.         return -1;
  215.     }
  216.     fseek(m->mfile,m->mbox[msg].start,0);
  217.     size = m->mbox[msg].size;
  218.  
  219.     if (noheader) {
  220.         /* skip header */
  221.         while (size > 0
  222.           && fgets(tstring,sizeof(tstring),m->mfile) != NULLCHAR) {
  223.             size -= strlen(tstring);
  224.             if (*tstring == '\n')
  225.                 break;
  226.         }
  227.     }
  228.     while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile) != NULLCHAR) {
  229.         size -= strlen(tstring);
  230.         fputs(tstring,tfile);
  231.         if (ferror(tfile)) {
  232.             tputs(Fileerr);
  233.             return -1;
  234.         }
  235.     }
  236.     return 0;
  237. }
  238.  
  239. /*  dodelmsg - delete message in current notesfile */
  240. int
  241. dodelmsg(argc,argv,p)
  242. int argc;
  243. char *argv[];
  244. void *p;
  245. {
  246.     int msg, i;
  247.     struct mbx *m = (struct mbx *) p;
  248.  
  249.     if (m->mfile == NULLFILE || m->security == 1) {
  250.         tputs(Nomail);
  251.         return 0;
  252.     }
  253.     for(i = 1; i < argc; ++i) {
  254.         msg = atoi(argv[i]);
  255.         if(msg < 1 || msg > m->nmsgs) {
  256.             tprintf(Badmsg,msg);
  257.             continue;
  258.         }
  259.         /* Check if we have permission to delete others mail */
  260.         if(!(m->privs & FTP_WRITE) && stricmp(m->area,m->name))
  261.             return -3;
  262.  
  263.         m->mbox[msg].status |= BM_DELETE;
  264.         usprintf(m->user,"Msg# %d killed\n",msg);
  265.         m->change = 1;
  266.     }
  267.     return 0;
  268. }
  269.  
  270. static int near
  271. lockit(struct mbx *m)
  272. {
  273.     int c, cnt = 0;
  274.  
  275.     while(mlock(Mailspool,m->area)) {
  276.         pause(1000L);                /* Wait one second */
  277.         if(++cnt == 10) {
  278.             cnt = 0;
  279.             c = tkeywait("Mail file is busy, Abort or Retry? ",1);
  280.             if (c == 'A' || c == 'a' || c == EOF) {
  281.                 mfclose(m);
  282.                 return 1;
  283.             }
  284.         }
  285.     }
  286.     return 0;
  287. }
  288.  
  289. /* close the temp file while coping mail back to the mailbox */
  290. int
  291. closenotes(m)
  292. struct mbx *m;
  293. {
  294.     struct    let *cmsg;
  295.     char *line, tstring[LINELEN], buf[256];
  296.     long size;
  297.     int i, nostatus = 0, nodelete;
  298.     FILE    *nfile;
  299.  
  300.     if (m->mfile == NULLFILE)
  301.         return 0;
  302.  
  303.     if(!m->change) {        /* no changes were made */
  304.         mfclose(m);
  305.         m->mboxsize = 0;
  306.         return 0;
  307.     }
  308.     /* If this area is a public message area, then we will not add a
  309.      * Status line to indicate that the message has been read.
  310.      */
  311.     nostatus = isarea(m->area);
  312.  
  313.     /* Don't delete messages from public message areas unless you are
  314.      * a BBS.
  315.      */
  316.     nodelete = (nostatus) ? !(m->privs & SYSOP_CMD) : 0;
  317.  
  318.     /* See if any messages have been forwarded, otherwise just close
  319.      * the file and return since there is nothing to write back.
  320.      */
  321.     if(nostatus && nodelete) {
  322.         for(i=1; i <= m->nmsgs; ++i)
  323.             if(m->mbox[i].status & BM_FORWARDED)
  324.                 break;
  325.         if(i > m->nmsgs) {
  326.             mfclose(m);
  327.             m->mboxsize = 0;
  328.             return 0;
  329.         }
  330.     }
  331.     line = tstring;
  332.     scanmail(m);
  333.     if(lockit(m))
  334.         return -1;
  335.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  336.     if ((nfile = open_file(buf,WRITE_TEXT,0,1)) == NULLFILE) {
  337.         mfclose(m);
  338.         m->mboxsize = 0;
  339.         rmlock(Mailspool,m->area);
  340.         return -1;
  341.     }
  342.     /* copy tmp file back to notes file */
  343.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
  344.         fseek(m->mfile,cmsg->start,0);
  345.         size = cmsg->size;
  346.         /* It is not possible to delete messages if nodelete is set */
  347.         if ((cmsg->status & BM_DELETE) && !nodelete)
  348.             continue;
  349.         /* copy the header */
  350.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  351.             size -= strlen(line);
  352.             if (*line == '\n') {
  353.                 if (cmsg->status & BM_FORWARDED)
  354.                     fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],m->name);
  355.                 if ((cmsg->status & BM_READ) != 0 && !nostatus)
  356.                     fprintf(nfile,"%sR\n",Hdrs[STATUS]);
  357.                 fprintf(nfile,"\n");
  358.                 break;
  359.             }
  360.             fputs(line,nfile);
  361.             /* pwait(NULL);  can cause problems if exiting NOS */
  362.         }
  363.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  364.             fputs(line,nfile);
  365.             size -= strlen(line);
  366.             /* pwait(NULL);   dont want no damaged files */
  367.             if (ferror(nfile)) {
  368.                 tputs(Fileerr);
  369.                 (void) fclose(nfile);
  370.                 mfclose(m);
  371.                 m->mboxsize = 0;
  372.                 rmlock(Mailspool,m->area);
  373.                 return -1;
  374.             }
  375.         }
  376.         pwait(NULL);    /* TEST */
  377.     }
  378.     m->nmsgs = 0;
  379.     if (!stricmp(m->name,m->area))
  380.         m->mysize = ftell(nfile); /* Update the size of our mailbox */
  381.     /* unlink a zero length file */
  382.     if (ftell(nfile) == 0L)
  383.         unlink(buf);
  384.     fclose(nfile);
  385.     mfclose(m);
  386.     m->mboxsize = 0;
  387.     rmlock(Mailspool,m->area);
  388.     return 0;
  389. }
  390.  
  391. /* Returns 1 if name is a public message Area, 0 otherwise */
  392. int
  393. isarea(name)
  394. char *name;
  395. {
  396.     char buf[LINELEN], *cp, *cp1;
  397.     FILE *fp;
  398.  
  399.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  400.         return 0;
  401.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
  402.         /* The first word on each line is all that matters */
  403.         cp = &buf[0];
  404.         while(isalnum(*cp) == 0)
  405.             cp++;
  406.         cp1 = cp;
  407.         while(isalnum(*cp1) != 0)
  408.             cp1++;
  409.         *cp1 = '\0';
  410.  
  411.         if(stricmp(name,cp) == 0) {    /* found it */
  412.             fclose(fp);
  413.             return 1;
  414.         }
  415.     }
  416.     fclose(fp);
  417.     return 0;
  418. }
  419.  
  420. /* read the next message or the current one if new */
  421. int
  422. doreadnext(argc,argv,p)
  423. int argc;
  424. char *argv[];
  425. void *p;
  426. {
  427.     char buf[10], *newargv[2];
  428.     struct mbx *m = (struct mbx *) p;
  429.  
  430.     if (m->mfile == NULLFILE)
  431.         return 0;
  432.  
  433.     if ((m->mbox[m->current].status & BM_READ) != 0) {
  434.         if (m->current == 1 && m->anyread == 0)
  435.             ;
  436.         else if (m->current < m->nmsgs) {
  437.             m->current++;
  438.         } else {
  439.             tputs("Last message\n");
  440.             return 0;
  441.         }
  442.     }
  443.     sprintf(buf,"%d",m->current);
  444.     newargv[0] = "read";
  445.     newargv[1] = buf;
  446.     m->anyread = 1;
  447.     return doreadmsg(2,newargv,p);
  448. }
  449.  
  450. /*  display message on the crt given msg number */
  451. int
  452. doreadmsg(argc,argv,p)
  453. int argc;
  454. char *argv[];
  455. void *p;
  456. {
  457.    int c, col, lin, msg, cnt, i, header, lastheader;
  458.    int    usemore = 0, verbose = 0, mbxheader = 0, DisableOutput = 0, pathcol;
  459.    int firstline = 0;
  460.    char buf[MAXCOL+2], *cp, *cp2;
  461.    long size;
  462.    struct mbx *m = (struct mbx *) p;
  463.  
  464.    if(m->security && !isarea(m->area))
  465.      return 0;
  466.  
  467.    if (m->mfile == NULLFILE) {
  468.      tputs(Nomail);
  469.      return 0;
  470.    }
  471.  
  472.    if(*argv[0] == 'v')
  473.      verbose = 1;            /* display all header lines */
  474.  
  475.    if(m->type == TIP || (Mbmore && m->type == TELNET))        /* DB3FL */
  476.      usemore = 1;
  477.  
  478.    lin = Nrows - 5;
  479.  
  480.    for(i = 1; i < argc; ++i) {
  481.      msg = atoi(argv[i]);
  482.      if( msg < 1 || msg > m->nmsgs) {
  483.        tprintf(Badmsg,msg);
  484.        return 0;
  485.      }
  486.      fseek(m->mfile,m->mbox[msg].start,0);
  487.      size = m->mbox[msg].size;
  488.      m->current = msg;
  489.      header = NOHEADER;
  490.  
  491.      tprintf("Msg #%d%s\n", msg,
  492.          m->mbox[msg].status & BM_DELETE ? " [Deleted]" : "");
  493.  
  494.      if ((m->mbox[msg].status & BM_READ) == 0) {
  495.        m->mbox[msg].status |= BM_READ;
  496.        m->change = 1;
  497.        m->newmsgs--;
  498.      }
  499.  
  500.      --lin;
  501.      col = 0;
  502.  
  503.      while (!feof(m->mfile) && size > 0) {
  504.        for (col = 0;  col < MAXCOL;) {
  505.      c = getc(m->mfile);
  506.      size--;
  507.      if (feof(m->mfile) || size == 0)    /* end this line */
  508.        break;
  509.      if (c == '\t') {
  510.        cnt = col + 8 - (col & 7);
  511.        if (cnt >= MAXCOL)             /* end this line */
  512.          break;
  513.        while (col < cnt)
  514.          buf[col++] = ' ';
  515.      }
  516.      else {
  517.        if (c == '\n')
  518.          break;
  519.        buf[col++] = c;
  520.      }
  521.        }
  522.        if(col < MAXCOL)
  523.      buf[col++] = '\n';
  524.        buf[col] = '\0';
  525.  
  526.        if(mbxheader > 0) {
  527.      /* Digest R: lines and display as a Path: line */
  528.      if(strncmp(buf,"R:",2) != 0 ||
  529.         (cp = strchr(buf,'@')) == NULLCHAR) {
  530.  
  531.        tputc('\n');
  532.        mbxheader = -1;     /* don't get here again */
  533.        verbose = 1;
  534.      }
  535.      else {
  536.        if(*(++cp) == ':')
  537.          ++cp;
  538.        for(cp2 = cp; isalnum(*cp2); ++cp2)  ;
  539.        *cp2 = '\0';
  540.        if(mbxheader++ == 1) {
  541.          tputs("Path: ");
  542.          pathcol = 5;
  543.          lin++;
  544.          firstline = 1;
  545.        }
  546.        else {
  547.          tputc('!');
  548.          ++lin;
  549.          if(++pathcol + strlen(cp) > MAXCOL-3) {
  550.            DisableOutput = 1;    /* disable output cause of -MORE- */
  551.            tputc('\n');
  552.            pathcol = 5;
  553.            if (!firstline)
  554.          lin--;
  555.            firstline = 0;
  556.          }
  557.        }
  558.        if (!DisableOutput)
  559.          tputs(cp);
  560.        pathcol += strlen(cp);
  561.      }
  562.        }
  563.  
  564.        if(col == 1 && !verbose && !mbxheader)
  565.      /* last header line reached */
  566.      mbxheader = 1;
  567.  
  568.        if(verbose)
  569.      tputs(buf);
  570.  
  571.        if (!verbose && !mbxheader) {
  572.      lastheader = header;
  573.  
  574.      if(!isspace(*buf))
  575.        header = htype(buf);
  576.      else
  577.        header = lastheader;
  578.  
  579.      switch(header) {
  580.      case TO:
  581.      case CC:
  582.      case FROM:
  583.      case DATE:
  584.      case SUBJECT:
  585.      case APPARTO:
  586.      case ORGANIZATION:
  587.        tputs(buf);
  588.        break;
  589.      default:
  590.        ++lin;
  591.      }
  592.        }
  593.  
  594.        col = 0;
  595.  
  596.        if(usemore && --lin == 0) {
  597.      c = tkeywait("SPACE for next page, Q to quit ",0);
  598.      lin = Nrows - 5;
  599.      if(c == -1 || c == 'q' || c == 'Q')
  600.        break;
  601.      if(c == '\n' || c == '\r')
  602.        lin = 2;
  603.        }
  604.  
  605.        if (DisableOutput) {
  606.      tputs("      ");        /* begin of a new path-line */
  607.      tputs(cp);
  608.      DisableOutput = 0;
  609.        }
  610.  
  611.      }
  612.    }
  613.    return 0;
  614. }
  615.  
  616. /* Set up m->to when replying to a message. The subject is returned in
  617.  * m->line.
  618.  */
  619. int
  620. mbx_reply(argc,argv,m,cclist,rhdr)
  621. int argc;
  622. char *argv[];
  623. struct mbx *m;
  624. struct list **cclist;    /* Pointer to buffer for pointers to cc recipients */
  625. char **rhdr;            /* Pointer to buffer for extra reply headers */
  626. {
  627.     char subject[MBXLINE], *cp, *msgid = NULLCHAR, *date = NULLCHAR, ch;
  628.     int i, msg, lastheader, header = NOHEADER;
  629.     long size;
  630.  
  631.     /* Free anything that might be allocated
  632.      * since the last call to mbx_to() or mbx_reply()
  633.      */
  634.     xfree(m->to);
  635.     m->to = NULLCHAR;
  636.     xfree(m->tofrom);
  637.     m->tofrom = NULLCHAR;
  638.     xfree(m->tomsgid);
  639.     m->tomsgid = NULLCHAR;
  640.     xfree(m->origto);
  641.     m->origto = NULLCHAR;
  642.     subject[0] = '\0';
  643.  
  644.     if (m->mfile == NULLFILE) {
  645.         usputs(m->user,(m->sid & MBX_SID) ? No : Nomail);
  646.         return -1;
  647.     }
  648.     /* Make sure that if SR has an argument, it consists of digits only */
  649.  
  650.     if ((argc > 1) && (*argv != NULLCHAR)) {
  651.         for (i=0; argv[i] != NULLCHAR; i++) {
  652.             ch = argv[1][i];
  653.             if(!isdigit(ch)) {
  654.                 usputs(m->user,(m->sid & MBX_SID) ?
  655.                     No : "Syntax error: SR <msg_number>\n");
  656.                 return -1;
  657.             }
  658.         }
  659.     }
  660.  
  661.     msg = (argc == 1) ? m->current : atoi(argv[1]);
  662.  
  663.     if(msg < 1 || msg > m->nmsgs) {
  664.         if(m->sid & MBX_SID)
  665.             usputs(m->user,No);
  666.         else
  667.             usprintf(m->user,Badmsg,msg);
  668.         return -1;
  669.     }
  670.     fseek(m->mfile,m->mbox[msg].start,0);
  671.     size = m->mbox[msg].size;
  672.     m->current = msg;
  673.     while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
  674.          size -= strlen(m->line);
  675.          if(m->line[0] == '\n')    /* end of header */
  676.           break;
  677.          rip(m->line);
  678.          lastheader = header;
  679.          if(!isspace(m->line[0])) {
  680.           header = htype(m->line);
  681.           lastheader = NOHEADER;
  682.          }
  683.          switch(header) {
  684.          case SUBJECT:
  685.           if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
  686.                strcpy(subject,&m->line[9]);
  687.           else
  688.                sprintf(subject,"Re: %s",&m->line[9]);
  689.           break;
  690.          case FROM:
  691.           if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) != NULLCHAR)
  692.                m->to = strxdup(cp);
  693.           break;
  694.          case REPLYTO:
  695.           if((cp = getaddress(m->line,0)) != NULLCHAR) {
  696.                xfree(m->to);
  697.                m->to = strxdup(cp);
  698.           }
  699.           break;
  700.          case MSGID:
  701.           xfree(msgid);
  702.           msgid = strxdup(&m->line[12]);
  703.           break;
  704.          case DATE:
  705.           xfree(date);
  706.           date = strxdup(&m->line[6]);
  707.           break;
  708.          case TO:
  709.          case CC:
  710.          case APPARTO:
  711.           /* Get addresses on To, Cc and Apparently-To lines */
  712.           cp = m->line;
  713.           m->line[strlen(cp)+1] = '\0';    /* add extra null at end */
  714.           for(;;) {
  715.                if((cp = getaddress(cp,lastheader == header ||
  716.                        cp != m->line)) == NULLCHAR)
  717.                 break;
  718.                addlist(cclist,cp,0);
  719.                /* skip to next address, if any */
  720.                cp += strlen(cp) + 1;
  721.           }
  722.           break;
  723.          }
  724.     }
  725.     if(msgid != NULLCHAR || date != NULLCHAR) {
  726.          *rhdr = mxallocw(LINELEN);
  727.          sprintf(*rhdr,"In-Reply-To: your message ");
  728.          if(date != NULLCHAR) {
  729.           sprintf(m->line,"of %s.\n",date);
  730.           strcat(*rhdr,m->line);
  731.           if(msgid != NULLCHAR)
  732.                strcat(*rhdr,"             ");
  733.          }
  734.          if(msgid != NULLCHAR) {
  735.           sprintf(m->line,"%s\n",msgid);
  736.           strcat(*rhdr,m->line);
  737.          }
  738.          xfree(msgid);
  739.          xfree(date);
  740.     }
  741.     strcpy(m->line,subject);
  742.     return 0;
  743. }
  744.  
  745. /* This function returns the length of a file. The proper thing would be
  746.  * to use stat(), but it fails when using DesqView together with Turbo-C
  747.  * code.
  748.  */
  749. static long near
  750. fsize(name)
  751. char *name;
  752. {
  753.     long cnt;
  754.     FILE *fp;
  755.  
  756.     if((fp = fopen(name,READ_TEXT)) == NULLFILE)
  757.         return -1L;
  758.     fseek(fp,0L,2);
  759.     cnt = ftell(fp);
  760.     fclose(fp);
  761.     return cnt;
  762. }
  763.  
  764. /* readnotes assumes that ifile is pointing to the first
  765.  * message that needs to be read.  For initial reads of a
  766.  * notesfile, this will be the beginning of the file.  For
  767.  * rereads when new mail arrives, it will be the first new
  768.  * message.
  769.  */
  770. static int near
  771. readnotes(m,ifile,update)
  772. struct mbx *m;
  773. FILE *ifile ;
  774. int update;    /* true if this is not the initial read of the notesfile */
  775. {
  776.     long cpos;
  777.     char tstring[LINELEN];
  778.     struct    let *cmsg = (struct let *)NULL;
  779.     char *line = tstring;
  780.  
  781.     while(fgets(line,LINELEN,ifile) != NULLCHAR) {
  782.         /* scan for begining of a message */
  783.         if(strncmp(line,"From ",5) == 0) {
  784.             cpos = ftell(m->mfile);
  785.             fputs(line,m->mfile);
  786.             if (m->nmsgs >= Maxlet) {
  787.                 usputs(m->user,(m->sid & MBX_SID) ?
  788.                     No : "Mailarea full - pse mail to sysop\n");
  789.                 mfclose(m);
  790.                 return -1;
  791.             }
  792.             m->nmsgs++;
  793.             cmsg = &m->mbox[m->nmsgs];
  794.             cmsg->start = cpos;
  795.             if(!update)
  796.                 cmsg->status = 0;
  797.             cmsg->size = strlen(line);
  798.             while (fgets(line,LINELEN,ifile) != NULLCHAR) {
  799.                 if (*line == '\n') { /* done header part */
  800.                     cmsg->size++;
  801.                     putc(*line, m->mfile);
  802.                     break;
  803.                 }
  804.                 if (htype(line) == STATUS) {
  805.                     if (line[8] == 'R')
  806.                         cmsg->status |= BM_READ;
  807.                     continue;
  808.                 }
  809.                 cmsg->size += strlen(line);
  810.                 if (fputs(line,m->mfile) == EOF) {
  811.                     tprintf("tmp file: %s",sys_errlist[errno]);
  812.                     mfclose(m);
  813.                     return -1;
  814.                 }
  815.             }
  816.         } else if (cmsg) {
  817.             cmsg->size += strlen(line);
  818.             fputs(line,m->mfile);
  819.             pwait(NULL);
  820.         }
  821.     }
  822.     return 0;
  823. }
  824.  
  825. static int near
  826. initnotes(m)
  827. struct mbx *m;
  828. {
  829.     FILE    *ifile;
  830.     struct    let *cmsg;
  831.     char buf[256];
  832.     int     i, ret;
  833.  
  834.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  835.     if ((ifile = fopen(buf,READ_TEXT)) == NULLFILE)
  836.         return 0;
  837.     fseek(ifile,0L,2);     /* go to end of file */
  838.     m->mboxsize = ftell(ifile);
  839.     rewind(ifile);
  840.     if(!stricmp(m->area,m->name)) /* our private mail area */
  841.         m->mysize = m->mboxsize;
  842.     if ((m->mfile = temp_file(0,1)) == NULLFILE) {
  843.         fclose(ifile);
  844.         return -1;
  845.     }
  846.  
  847. #ifdef    SETVBUF
  848.     if (stdinbuf == NULLCHAR)
  849.         stdinbuf = mxallocw(MYBUF);
  850.     setvbuf(ifile, stdinbuf, _IOFBF, MYBUF);
  851.     if (stdoutbuf == NULLCHAR)
  852.         stdoutbuf = mxallocw(MYBUF);
  853.     setvbuf(m->mfile, stdoutbuf, _IOFBF, MYBUF);
  854. #endif
  855.  
  856.     m->nmsgs = m->current = m->change = m->newmsgs = m->anyread = 0;
  857.  
  858.     /* Allocate space for reading messages */
  859.     xfree((char *)m->mbox);
  860.     m->mbox = (struct let *)cxallocw(Maxlet+1,sizeof(struct let));
  861.     ret = readnotes(m,ifile,0);
  862.     fclose(ifile);
  863.  
  864. #ifdef SETVBUF
  865.     xfree(stdinbuf);
  866.     stdinbuf = NULLCHAR;
  867. #endif
  868.  
  869.     if (ret != 0)
  870.         return -1;
  871.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)
  872.         if ((cmsg->status & BM_READ) == 0) {
  873.             m->newmsgs++;
  874.             if (m->current == 0)
  875.                 m->current = i;
  876.         }
  877.     /* start at one if no new messages */
  878.     if (m->current == 0)
  879.         m->current++;
  880.  
  881.     return 0;
  882. }
  883.  
  884. void
  885. scanmail(m)         /* Get any new mail */
  886. struct mbx *m;
  887. {
  888.     FILE *nfile;
  889.     int ret, cnt;
  890.     char buf[256];
  891.     long diff;
  892.  
  893.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  894.     if((diff = fsize(buf) - m->mboxsize) == 0L)
  895.         return;
  896.  
  897.     if(lockit(m))
  898.         return;
  899.     if(m->mfile == NULLFILE || diff < 0L) {
  900.         /* This is the first time scanmail is called, or the
  901.          * mail file size has decreased. In the latter case,
  902.          * any changes we did to this area will be lost, but this
  903.          * is not fatal.
  904.          */
  905.         ret = initnotes(m);
  906.         rmlock(Mailspool,m->area);
  907.         if(ret != 0) {
  908.             m->nmsgs = m->current = m->change = m->newmsgs = m->anyread = 0;
  909.             mfclose(m);
  910.         }
  911.         return;
  912.     }
  913.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  914.     if ((nfile = fopen(buf,READ_TEXT)) != NULLFILE) {
  915.         /* rewind tempfile */
  916.         fseek(m->mfile,0L,0);
  917.         cnt = m->nmsgs;
  918.         /* Reread all messages since size they may have changed
  919.          * in size after a X-Forwarded-To line was added.
  920.          */
  921.         m->nmsgs = 0;
  922.         ret = readnotes(m,nfile,1);   /* get the mail */
  923.         m->newmsgs += m->nmsgs - cnt;
  924.         m->mboxsize = ftell(nfile);
  925.         if(!stricmp(m->name,m->area))
  926.             m->mysize = m->mboxsize;
  927.         fclose(nfile);
  928.         if (ret != 0)
  929.             tputs(Fileerr);
  930.     }
  931.     rmlock(Mailspool,m->area);
  932. }
  933.  
  934. /* Check if the private mail area has changed */
  935. long
  936. isnewprivmail(m)
  937. struct mbx *m;
  938. {
  939.     char buf[256];
  940.     long cnt = m->mysize;
  941.  
  942.     sprintf(buf,"%s/%s.txt",Mailspool,m->name);
  943.     m->mysize = fsize(buf);
  944.     return m->mysize - cnt; /* != 0 not more than once */
  945. }
  946.  
  947. char *Hdrs[] = {
  948.     "Approved: ",
  949.     "From: ",
  950.     "To: ",
  951.     "Date: ",
  952.     "Message-Id: ",
  953.     "Subject: ",
  954.     "Received: ",
  955.     "Sender: ",
  956.     "Reply-To: ",
  957.     "Status: ",
  958.     "X-BBS-Msg-Type: ",
  959.     "X-Forwarded-To: ",
  960.     "Cc: ",
  961.     "Return-Receipt-To: ",
  962.     "Apparently-To: ",
  963.     "Errors-To: ",
  964.     "Organization: ",
  965.     NULLCHAR
  966. };
  967.  
  968. /* return the header type */
  969. int
  970. htype(s)
  971. char *s;
  972. {
  973.     char i, *p = s;
  974.  
  975.     /* check to see if there is a ':' before and white space */
  976.     while (*p != '\0' && *p != ' ' && *p != ':')
  977.         p++;
  978.     if (*p != ':')
  979.         return NOHEADER;
  980.  
  981.     for (i = 0; Hdrs[i] != NULLCHAR; i++) {
  982.         if (strnicmp(Hdrs[i],s,strlen(Hdrs[i])) == 0)
  983.             return i;
  984.     }
  985.     return UNKNOWN;
  986. }
  987.  
  988. /* Parse a string in the "Text: <user@host>" or "Text: user@host (Text)"
  989.  * format for the address user@host.
  990.  */
  991. char *
  992. getaddress(string,cont)
  993. char *string;
  994. int cont;        /* true if string is a continued header line */
  995. {
  996.     char *cp, *ap = NULLCHAR;
  997.     int par = 0;
  998.  
  999.     if((cp = getname(string)) != NULLCHAR) /* Look for <> style address */
  1000.          return cp;
  1001.     cp = string;
  1002.     if(!cont)
  1003.          if((cp = strchr(string,':')) == NULLCHAR)    /* Skip the token */
  1004.           return NULLCHAR;
  1005.          else
  1006.           ++cp;
  1007.     for(; *cp != '\0'; ++cp) {
  1008.          if(par && *cp == ')') {
  1009.           --par;
  1010.           continue;
  1011.          }
  1012.          if(*cp == '(')        /* Ignore text within parenthesis */
  1013.           ++par;
  1014.          if(par)
  1015.           continue;
  1016.          if(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == ',') {
  1017.           if(ap != NULLCHAR)
  1018.                break;
  1019.           continue;
  1020.          }
  1021.          if(ap == NULLCHAR)
  1022.           ap = cp;
  1023.     }
  1024.     *cp = '\0';
  1025.     return ap;
  1026. }
  1027.  
  1028. /* Print prompt and read one character, telnet version */
  1029. static int near
  1030. tkeywait(prompt,flush)
  1031. char *prompt;    /* Optional prompt */
  1032. int flush;    /* Flush queued input? */
  1033. {
  1034.     int c, i, oldimode,oldomode;
  1035.  
  1036.     if(flush && socklen(Curproc->input,0) != 0)
  1037.         recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
  1038.  
  1039.     if(prompt == NULLCHAR)
  1040.         prompt = "Hit enter to continue";
  1041.     usprintf(Curproc->output,"%s%c%c%c",prompt,IAC,WILL,TN_ECHO);
  1042.     usflush(Curproc->output);
  1043.  
  1044.     /* discard the response */
  1045.  
  1046.     oldimode = sockmode(Curproc->input,SOCK_BINARY);
  1047.     oldomode = sockmode(Curproc->output,SOCK_BINARY);
  1048.  
  1049.     while((c = rrecvchar(Curproc->input)) == IAC){
  1050.         c = rrecvchar(Curproc->input);
  1051.         if(c > 250 && c < 255)
  1052.             rrecvchar(Curproc->input);
  1053.     }
  1054.  
  1055.     sockmode(Curproc->output,oldomode);
  1056.     sockmode(Curproc->input,oldimode);
  1057.  
  1058.     /* Get rid of the prompt */
  1059.     for(i = strlen(prompt);i != 0; i--)
  1060.         usputs(Curproc->output,"\b \b");
  1061.     usprintf(Curproc->output,"%c%c%c",IAC,WONT,TN_ECHO);
  1062.     usflush(Curproc->output);
  1063.     return c;
  1064. }
  1065.